package com.quickfile.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import com.quickfile.File;
import com.quickfile.FileInputStream;

public class ZipFile {

	private String name;
	private byte[] content;
	private Map<String, ZipEntry> zipEntryMap;

	public ZipFile(File file) throws IOException {
		this(file, 0);
	}

	public ZipFile(String name) throws IOException {
		this(File.newInstance(name), 0);
	}

	public ZipFile(File file, int mode) throws IOException {
		name = file.getPath();

		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		InputStream inputStream = FileInputStream.newInstance(file);
		IoUtil.copyStream(inputStream, outputStream, file.length());
		content = outputStream.toByteArray();
		outputStream.close();
		inputStream.close();

		zipEntryMap = new HashMap<String, ZipEntry>();
		checkZipInputStream(new DoWithZipIntry() {

			@Override
			public boolean doSomething(ZipInputStream zipInputStream,
					ZipEntry zipEntry) {
				zipEntryMap.put(zipEntry.getName(), zipEntry);
				return true;
			}

		}, true);
	}

	public void close() throws IOException {
		content = null;
	}

	public interface DoWithZipIntry {
		public boolean doSomething(ZipInputStream zipInputStream,
				ZipEntry zipEntry);
	}

	private void checkZipInputStream(DoWithZipIntry doWithZipIntry,
			boolean closeStream) throws IOException {
		ZipInputStream zipInputStream = null;
		try {
			zipInputStream = new ZipInputStream(new ByteArrayInputStream(
					content));
			while (true) {
				ZipEntry zipEntry = zipInputStream.getNextEntry();
				if (zipEntry == null)
					break;
				if (!doWithZipIntry.doSomething(zipInputStream, zipEntry))
					break;
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			if (closeStream && zipInputStream != null)
				zipInputStream.close();
		}
	}

	public Enumeration<? extends ZipEntry> entries() throws IOException {
		final Vector v = new Vector();
		for (String name : zipEntryMap.keySet()) {
			v.add(zipEntryMap.get(name));
		}
		return v.elements();
	}

	public ZipEntry getEntry(final String name) throws IOException {
		for (String key : zipEntryMap.keySet()) {
			ZipEntry zipEntry = zipEntryMap.get(key);
			String zipEntryName = zipEntry.getName();
			if (zipEntryName.equals(name))
				return zipEntry;
		}
		return null;
	}

	public InputStream getInputStream(final ZipEntry entry) throws IOException {
		final List<InputStream> rtnInputStreamList = new ArrayList<InputStream>();
		checkZipInputStream(new DoWithZipIntry() {

			@Override
			public boolean doSomething(ZipInputStream zipInputStream,
					ZipEntry zipEntry) {
				if (zipEntry.getName().equals(entry.getName())) {
					rtnInputStreamList.add(zipInputStream);
					return false;
				}
				return true;
			}

		}, false);
		if (rtnInputStreamList.isEmpty())
			return null;
		return rtnInputStreamList.get(0);
	}

	public String getName() {
		return name;
	}

	public int size() throws IOException {
		return zipEntryMap.size();
	}
}
